home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
3D GFX
/
3D GFX.iso
/
amiutils
/
i_l
/
irit5
/
irit
/
inptevl3.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-12-30
|
38KB
|
1,034 lines
/*****************************************************************************
* "Irit" - the 3d (not only polygonal) solid modeller. *
* *
* Written by: Gershon Elber Ver 0.2, Mar. 1990 *
******************************************************************************
* Module to evaluate the binary tree generated by the InptPrsr module. *
* All the objects are handled the same but the numerical one, which is *
* moved as a RealType and not as an object (only internally within this *
* module) as it is frequently used and consumes much less memory this way. *
* Note this module is par of InptPrsr module and was splited only because *
* of text file sizes problems... *
*****************************************************************************/
#include <stdio.h>
#include <ctype.h>
#include <math.h>
#include <string.h>
#include "program.h"
#include "ctrl-brk.h"
#include "objects.h"
#include "allocate.h"
#include "inptprsg.h"
#include "inptprsl.h"
#include "windows.h"
static int
GlblDebugFuncLevel = 0;
static void RebindVariable(ParseTree *Root, IPObjectStruct *PObj, int FreeOld);
static ParseTree *InptEvalFetchExpression(ParseTree *Root, int i, int n);
static int InptEvalCountNumExpressions(ParseTree *Root);
static void InptEvalDeleteFunc(UserDefinedFuncDefType *UserFunc,
int DeleteSelf);
/*****************************************************************************
* DESCRIPTION: M
* Prints help on the given subject HelpHeader. M
* A match is if the HelpHeader isa prefix of help file line. M
* *
* PARAMETERS: M
* HelpHeader: Subject of help needed. M
* *
* RETURN VALUE: M
* void M
* *
* KEYWORDS: M
* InptEvalPrintHelp M
*****************************************************************************/
void InptEvalPrintHelp(char *HelpHeader)
{
static char
*DefaultHelp = NULL;
int i;
char *Path, s[LINE_LEN];
FILE *f;
Path = searchpath(GlblHelpFileName);
if (DefaultHelp == NULL)
DefaultHelp = IritStrdup("Commands");
if (strlen(HelpHeader) == 0)
HelpHeader = DefaultHelp; /* Print a list of all commands. */
if ((f = fopen(Path, "r")) == NULL) {
sprintf(s, "Cannot open help file \"%s\".\n", GlblHelpFileName);
WndwInputWindowPutStr(s);
return;
}
for (i = 0; i < (int) strlen(HelpHeader); i++)
if (islower(HelpHeader[i]))
HelpHeader[i] = toupper(HelpHeader[i]);
while (fgets(s, LINE_LEN-1, f) != NULL) {
if (strncmp(HelpHeader, s, strlen(HelpHeader)) == 0) {
/* Found match - print it. */
while (fgets(s, LINE_LEN-1, f) != NULL && s[0] != '$') {
if (s[strlen(s) - 1] < ' ')
s[strlen(s) - 1] = 0; /* No CR/LF. */
WndwInputWindowPutStr(&s[1]); /* Skip char 1. */
}
fclose(f);
return;
}
}
fclose(f);
sprintf(s, "No help on %s\n", HelpHeader);
WndwInputWindowPutStr(s);
}
/*****************************************************************************
* DESCRIPTION: M
* Compares two objects with comparison operator as in Root. M
* *
* PARAMETERS: M
* Root: Type of comparison requested (=, <, >, etc.). M
* Left, Right: Two objects to compare. M
* IError: Type of error if was one. M
* CError: Description of error if was one. M
* *
* RETURN VALUE: M
* ParseTree *: Comparison result as a numeric value of >0, 0, <0. M
* *
* KEYWORDS: M
* InptEvalCompareObject M
*****************************************************************************/
ParseTree *InptEvalCompareObject(ParseTree *Root,
ParseTree *Left,
ParseTree *Right,
InptPrsrEvalErrType *IError,
char *CError)
{
int OnlyEquality = TRUE;
RealType
Cmp = 0.0;
if (Left -> PObj -> ObjType != Right -> PObj -> ObjType) {
*IError = IE_ERR_INCOMPARABLE_TYPES;
strcpy(CError, "");
return NULL;
}
switch (Left -> PObj -> ObjType) {
case IP_OBJ_NUMERIC:
Cmp = SIGN(Left -> PObj -> U.R - Right -> PObj -> U.R);
OnlyEquality = FALSE;
break;
case IP_OBJ_POINT:
Cmp = PT_APX_EQ(Left -> PObj -> U.Pt,
Right -> PObj -> U.Pt) == 0;
break;
case IP_OBJ_VECTOR:
Cmp = PT_APX_EQ(Left -> PObj -> U.Vec,
Right -> PObj -> U.Vec) == 0;
break;
case IP_OBJ_PLANE:
Cmp = PLANE_APX_EQ(Left -> PObj -> U.Plane,
Right -> PObj -> U.Plane) == 0;
break;
case IP_OBJ_STRING:
Cmp = strcmp(Left -> PObj -> U.Str, Right -> PObj -> U.Str);
OnlyEquality = FALSE;
break;
default:
break;
}
switch (Root -> NodeKind) {
case CMP_EQUAL:
Cmp = Cmp == 0.0;
break;
case CMP_NOTEQUAL:
Cmp = Cmp != 0.0;
break;
case CMP_LSEQUAL:
case CMP_GTEQUAL:
case CMP_LESS:
case CMP_GREAT:
if (OnlyEquality) {
*IError = IE_ERR_ONLYEQUALITY_TEST;
strcpy(CError, "");
return NULL;
}
else {
switch (Root -> NodeKind) {
case CMP_LSEQUAL:
Cmp = Cmp <= 0.0;
break;
case CMP_GTEQUAL:
Cmp = Cmp >= 0.0;
break;
case CMP_LESS:
Cmp = Cmp < 0.0;
break;
case CMP_GREAT:
Cmp = Cmp > 0.0;
break;
}
}
break;
default:
IritFatalError("A comparison operator expected.");
break;
}
Root -> PObj = GenNUMValObject(Cmp);
return Root;
}
/*****************************************************************************
* DESCRIPTION: M
* Executes the IF expression. M
* *
* PARAMETERS: M
* Cond: To evaluate in the IF sentence. M
* CondTrue: Optional, execute if Cond is TRUE. M
* CondFalse: Optional, execute if Cond is FALSE. M
* *
* RETURN VALUE: M
* void M
* *
* KEYWORDS: M
* InptEvalIfCondition M
*****************************************************************************/
void InptEvalIfCondition(ParseTree *Cond,
ParseTree *CondTrue,
ParseTree *CondFalse)
{
if ((Cond = InptPrsrEvalTree(Cond, 1)) != NULL &&
Cond -> PObj != NULL &&
IP_IS_NUM_OBJ(Cond -> PObj)) {
if (APX_EQ(Cond -> PObj -> U.R, 0.0)) {
if (CondFalse != NULL)
InptPrsrEvalTree(CondFalse, 0);
}
else {
if (CondTrue != NULL)
InptPrsrEvalTree(CondTrue, 0);
}
}
else {
IPGlblEvalError = IE_ERR_IF_HAS_NO_COND;
strcpy(IPGlblCharData, "");
}
}
/*****************************************************************************
* DESCRIPTION: M
* Executes the FOR expression loop. M
* As InptPrsrEvalTree routine is destructive on its input tree, we must M
* make a copy of the body before executing it! M
* We wish we could access the loop variable directly, but the user might M
* free them in the loop - so me must access it by name. M
* *
* PARAMETERS: M
* PStart: Initailization expression. M
* PInc: Increment expression. M
* PEnd: Termination expression. M
* PBody: Body of loop expression. M
* *
* RETURN VALUE: M
* void M
* *
* KEYWORDS: M
* InptEvalForLoop M
*****************************************************************************/
void InptEvalForLoop(ParseTree *PStart,
ParseTree *PInc,
ParseTree *PEnd,
ParseTree *PBody)
{
int i, NumOfExpr, LoopCount;
char
*LoopVarName = NULL;
RealType LoopVar, StartVal, Increment, EndVal;
ParseTree *PTemp;
IPObjectStruct *PLoopVar;
/* Find the only two cases where loop variable is allowed - when then */
/* given starting value is a parameter, or assignment to parameter... */
if (PStart -> NodeKind == PARAMETER)
LoopVarName = PStart -> PObj -> Name;
else if (PStart -> NodeKind == EQUAL &&
PStart -> Left -> NodeKind == PARAMETER) {
LoopVarName = PStart -> Left -> PObj -> Name;
/* Rebind the iteration variable to body - it might be new: */
RebindVariable(PBody, PStart -> Left -> PObj, FALSE);
if (GetObject(LoopVarName) == NULL) /* It is really new. */
PStart -> Left -> PObj -> Count++;
}
PStart = InptPrsrEvalTree(PStart, 1); /* Evaluate starting value. */
PInc = InptPrsrEvalTree(PInc, 1); /* Evaluate increment value. */
PEnd = InptPrsrEvalTree(PEnd, 1); /* Evaluate end value. */
if (IPGlblEvalError ||
PStart == NULL || PInc == NULL || PEnd == NULL)
return;
StartVal = PStart -> PObj -> U.R;
Increment = PInc -> PObj -> U.R;
EndVal = PEnd -> PObj -> U.R;
/* Num. of expr. in the body. */
NumOfExpr = InptEvalCountNumExpressions(PBody);
for (LoopVar = StartVal, LoopCount = 0;
APX_EQ(LoopVar, EndVal) ||
(Increment > 0 ? LoopVar <= EndVal : LoopVar >= EndVal);
LoopVar += Increment, LoopCount++) {
if (IPGlblEvalError || GlblFatalError)
return;
if (LoopVarName != NULL) {
if ((PLoopVar = GetObject(LoopVarName)) != NULL &&
IP_IS_NUM_OBJ(PLoopVar))
PLoopVar -> U.R = LoopVar; /* Update loop var. */
else {
IPGlblEvalError = IE_ERR_MODIF_ITER_VAR;
strcpy(IPGlblCharData, LoopVarName);
}
}
for (i = 0; i < NumOfExpr; i++) {
PTemp = InptEvalFetchExpression(PBody, i, NumOfExpr);
if (LoopCount == 0 && InptPrsrTypeCheck(PTemp, 0) == ERROR_EXPR)
return;
else {
if (LoopVar == EndVal) {
/* Use the original tree. Note we must evaluate the */
/* original tree at least once as ObjType's are updated. */
InptPrsrEvalTree(PTemp, 0); /* Eval as its top level... */
}
else {
PTemp = InptPrsrCopyTree(PTemp);
InptPrsrEvalTree(PTemp, 0); /* Eval as its top level... */
InptPrsrFreeTree(PTemp); /* Not needed any more. */
}
}
}
}
}
/*****************************************************************************
* DESCRIPTION: *
* Rebinds a variable - given a tree, scan it and update each occurance of *
* that variable to point to PObj. *
* *
* PARAMETERS: *
* Root: Tree to rebind. *
* PObj: Variable to rebind to. *
* FreeOld: Should we free old instance of PObj? *
* *
* RETURN VALUE: *
* void *
*****************************************************************************/
static void RebindVariable(ParseTree *Root, IPObjectStruct *PObj, int FreeOld)
{
if (Root == NULL)
return;
if (IS_FUNCTION(Root -> NodeKind)) { /* All the functions. */
RebindVariable(Root -> Right, PObj, FreeOld);
return;
}
switch (Root -> NodeKind) {
case DIV:
case MINUS:
case MULT:
case PLUS:
case POWER:
case COMMA:
case COLON:
case EQUAL:
case CMP_EQUAL:
case CMP_NOTEQUAL:
case CMP_LSEQUAL:
case CMP_GTEQUAL:
case CMP_LESS:
case CMP_GREAT:
case BOOL_OR:
case BOOL_AND:
RebindVariable(Root -> Right, PObj, FreeOld);
RebindVariable(Root -> Left, PObj, FreeOld);
return;
case UNARMINUS:
case BOOL_NOT:
RebindVariable(Root -> Right, PObj, FreeOld);
return;
case NUMBER:
return;
case PARAMETER:
case STRING:
if (strcmp(Root -> PObj -> Name, PObj -> Name) == 0) {
if (FreeOld && IP_IS_UNDEF_OBJ(Root -> PObj))
IPFreeObject(Root -> PObj);
Root -> PObj = PObj;
}
return;
case TOKENSTART:
return;
default:
IritFatalError("RebindVariable: Undefined ParseTree type, exit");
}
}
/*****************************************************************************
* DESCRIPTION: M
* Marks all undefined objects in bindings as "to be assigned". M
* *
* PARAMETERS: M
* Root: Tree to rebind. M
* *
* RETURN VALUE: M
* void M
* *
* KEYWORDS: M
* IritPrsrMarkToBeAssigned M
*****************************************************************************/
void IritPrsrMarkToBeAssigned(ParseTree *Root)
{
if (Root == NULL)
return;
if (IS_FUNCTION(Root -> NodeKind)) { /* All the functions. */
IritPrsrMarkToBeAssigned(Root -> Right);
return;
}
switch (Root -> NodeKind) {
case DIV:
case MINUS:
case MULT:
case PLUS:
case POWER:
case COMMA:
case COLON:
case EQUAL:
case CMP_EQUAL:
case CMP_NOTEQUAL:
case CMP_LSEQUAL:
case CMP_GTEQUAL:
case CMP_LESS:
case CMP_GREAT:
case BOOL_OR:
case BOOL_AND:
IritPrsrMarkToBeAssigned(Root -> Right);
IritPrsrMarkToBeAssigned(Root -> Left);
return;
case UNARMINUS:
case BOOL_NOT:
IritPrsrMarkToBeAssigned(Root -> Right);
return;
case NUMBER:
case STRING:
return;
case PARAMETER:
if (IP_IS_UNDEF_OBJ(Root -> PObj))
SET_TO_BE_ASSIGN_OBJ(Root -> PObj);
return;
case TOKENSTART:
return;
default:
IritFatalError("IritPrsrMarkToBeAssigned: Undefined ParseTree type, exit");
}
}
/*****************************************************************************
* DESCRIPTION: M
* Creates an OBJECT LIST object out of all parameters. M
* *
* PARAMETERS: M
* PObjParams: To insert into one list object. M
* *
* RETURN VALUE: M
* IPObjectStruct *: A list object with all the parameters, or NULL if M
* error. M
* *
* KEYWORDS: M
* InptEvalGenObjectList M
*****************************************************************************/
IPObjectStruct *InptEvalGenObjectList(ParseTree *PObjParams)
{
int i, NumOfParams;
ParseTree *Param;
IPObjectStruct *PObj;
NumOfParams = InptEvalCountNumParameters(PObjParams);
PObj = IPAllocObject("", IP_OBJ_LIST_OBJ, NULL);
for (i = 0; i < NumOfParams; i++) {
if ((Param = InptPrsrEvalTree(InptEvalFetchParameter(PObjParams, i,
NumOfParams),
1)) == NULL) {
IPFreeObject(PObj);
return NULL;
}
if (IP_IS_UNDEF_OBJ(Param -> PObj)) {
IPGlblEvalError = IE_ERR_IP_OBJ_UNDEFINED;
strcpy(IPGlblCharData, Param -> PObj -> Name);
ListObjectInsert(PObj, i, NULL);
IPFreeObject(PObj);
return NULL;
}
ListObjectInsert(PObj, i, Param -> PObj);
Param -> PObj -> Count++; /* Increase number of references. */
}
ListObjectInsert(PObj, NumOfParams, NULL);
return PObj;
}
/*****************************************************************************
* DESCRIPTION: M
* Creates a Control Point Object out of all parameters. M
* *
* PARAMETERS: M
* PObjParams: To create a control pointwith. M
* *
* RETURN VALUE: M
* IPObjectStruct *: A control point object, or NULL if error. M
* *
* KEYWORDS: M
* InptEvalCtlPtFromParams M
*****************************************************************************/
IPObjectStruct *InptEvalCtlPtFromParams(ParseTree *PObjParams)
{
int i, NumPts, NumOfParams, PtType,
CoordCount = 0;
ParseTree *Param;
IPObjectStruct *PObj;
NumOfParams = InptEvalCountNumParameters(PObjParams);
PObj = IPAllocObject("", IP_OBJ_CTLPT, NULL);
for (i = 0; i < NumOfParams; i++) {
if ((Param = InptPrsrEvalTree(InptEvalFetchParameter(PObjParams, i,
NumOfParams),
1)) == NULL) {
IPFreeObject(PObj);
return NULL;
}
if (!IP_IS_NUM_OBJ(Param -> PObj)) {
IPGlblEvalError = IE_ERR_TYPE_MISMATCH;
strcpy(IPGlblCharData, "Numeric data expected");
IPFreeObject(PObj);
return NULL;
}
if (i == 0) {
PtType = PObj -> U.CtlPt.PtType =
(CagdPointType) Param -> PObj -> U.R;
switch (PtType) {
case CAGD_PT_E1_TYPE:
case CAGD_PT_E2_TYPE:
case CAGD_PT_E3_TYPE:
case CAGD_PT_E4_TYPE:
case CAGD_PT_E5_TYPE:
NumPts = CAGD_NUM_OF_PT_COORD(PtType);
CoordCount = 1;
break;
case CAGD_PT_P1_TYPE:
case CAGD_PT_P2_TYPE:
case CAGD_PT_P3_TYPE:
case CAGD_PT_P4_TYPE:
case CAGD_PT_P5_TYPE:
NumPts = CAGD_NUM_OF_PT_COORD(PtType) + 1;
CoordCount = 0;
break;
default:
IPGlblEvalError = IE_ERR_TYPE_MISMATCH;
strcpy(IPGlblCharData,
"E{1-5} or P{1-5} point type expected");
IPFreeObject(PObj);
return NULL;
}
if (NumOfParams - 1 != NumPts) {
IPGlblEvalError = IE_ERR_NUM_PRM_MISMATCH;
sprintf(IPGlblCharData, "%d expected", NumPts);
IPFreeObject(PObj);
return NULL;
}
}
else
PObj -> U.CtlPt.Coords[CoordCount++] = Param -> PObj -> U.R;
}
return PObj;
}
/*****************************************************************************
* DESCRIPTION: *
* Fetches the i'th expression out of a tree represent n expressions *
* (0 <= i < n) seperated by colon. Similar to InptEvalFetchParameter rtn. *
* *
* PARAMETERS: *
* Root: To fetch an expression from. *
* i: The expression to fetch. *
* n: Total number of expressions. *
* *
* RETURN VALUE: *
* ParseTree *: Fetched expression. *
*****************************************************************************/
static ParseTree *InptEvalFetchExpression(ParseTree *Root, int i, int n)
{
int j;
for (j = 0; j < i; j++)
Root = Root -> Right;
if (i == n - 1)
return Root;
else
return Root -> Left;
}
/*****************************************************************************
* DESCRIPTION: *
* Count the number of expressions seperated by a COLON that are given in the *
* tree ROOT. This routine is similar to InptEvalCountNumParameters. *
* *
* PARAMETERS: *
* Root: To count number of expressions. *
* *
* RETURN VALUE: *
* int: Number of expressions found. *
*****************************************************************************/
static int InptEvalCountNumExpressions(ParseTree *Root)
{
int i = 1;
while (Root -> NodeKind == COLON) {
i++;
Root = Root -> Right;
}
return i;
}
/*****************************************************************************
* DESCRIPTION: M
* Handles a user defined function or procedure. M
* A user defined function or proecdure is of the sepcial form: M
* M
* FuncName = {function | procedure}(Param1, Param2, ... , ParamN): V
* LocalVar1: LocalVar2: ... LocalVarN: V
* BodyExpr1: BodyExpr2: ... BodYExprN; V
* M
* This special form is decomposed into the following sections: M
* 1. Parameter list as a list of IPObjectStructs. M
* 2. Local variable list as a list of IPObjectStructs. M
* 3. Body expression list as a Parsing tree. M
* M
* Defined function is saved in the global UserDefinedFuncList list. M
* *
* PARAMETERS: M
* FuncDef: Parse tree of user defined function. M
* *
* RETURN VALUE: M
* void M
* *
* KEYWORDS: M
* InptEvalDefineFunc M
*****************************************************************************/
void InptEvalDefineFunc(ParseTree *FuncDef)
{
int NewFunc;
char
*Name = FuncDef -> Left -> Left -> PObj -> Name;
ParseTree *Body, *PTmp;
UserDefinedFuncDefType *UserFunc;
IPObjectStruct *PObjTail, *PObj, *PObjTmp;
for (UserFunc = UserDefinedFuncList;
UserFunc != NULL;
UserFunc = UserFunc -> Pnext) {
if (strcmp(UserFunc -> FuncName, Name) == 0) {
InptEvalDeleteFunc(UserFunc, FALSE);
break;
}
}
if (UserFunc == NULL) {
UserFunc = (UserDefinedFuncDefType *)
IritMalloc(sizeof(UserDefinedFuncDefType));
UserFunc -> Params = UserFunc -> LocalVars = NULL;
UserFunc -> Body = NULL;
UserFunc -> NumParams = 0;
NewFunc = TRUE;
}
else {
InptEvalDeleteFunc(UserFunc, FALSE);
NewFunc = FALSE;
}
/* Mark it as a function or procedure. */
UserFunc -> IsFunction =
FuncDef -> Left -> Right -> NodeKind == USERFUNCDEF;
/* Get the function name. */
PTmp = FuncDef -> Left -> Left;
strncpy(UserFunc -> FuncName, Name, FUNC_NAME_LEN - 1);
if (PTmp -> PObj -> ObjType == IP_OBJ_UNDEF) {
/* Free it since not such object exists. */
IPFreeObject(PTmp -> PObj);
PTmp -> PObj = NULL;
}
/* Remove the object with function name and the return variable if they */
/* were undefined and were created because of the parsing of function. */
if ((PObj = GetObject(Name)) != NULL && PObj -> ObjType == IP_OBJ_UNDEF)
DeleteObject(PObj, TRUE);
if ((PObj = GetObject("RETURN")) != NULL &&
PObj -> ObjType == IP_OBJ_UNDEF)
DeleteObject(PObj, TRUE);
/* Save the list of parameters. */
for (PTmp = FuncDef -> Left -> Right -> Right, PObjTail = NULL;
PTmp != NULL && PTmp -> NodeKind == COMMA;
PTmp = PTmp -> Right) {
if (PTmp -> Left -> NodeKind == PARAMETER) {
Name = PTmp -> Left -> PObj -> Name;
/* Make sure we do not have duplicated names in param. list. */
for (PObjTmp = UserFunc -> Params;
PObjTmp != NULL;
PObjTmp = PObjTmp -> Pnext) {
if (strcmp(Name, PObjTmp -> Name) == 0) {
IPGlblEvalError = IE_ERR_IP_USERFUNC_DUP_VAR;
sprintf(IPGlblCharData, "Func \"%s\", Variable \"%s\"",
UserFunc -> FuncName, Name);
InptEvalDeleteFunc(UserFunc, TRUE);
return;
}
}
/* Create a new object with same name but undefined type. */
if (UserFunc -> Params == NULL)
UserFunc -> Params = PObjTail =
IPAllocObject(Name, IP_OBJ_UNDEF, NULL);
else {
PObjTail -> Pnext = IPAllocObject(Name, IP_OBJ_UNDEF, NULL);
PObjTail = PObjTail -> Pnext;
}
/* Make sure there is no undefined object by that name in global */
/* list from the parsing stage. If so - remove it. */
if ((PObj = GetObject(Name)) != NULL &&
PObj -> ObjType == IP_OBJ_UNDEF)
DeleteObject(PObj, TRUE);
}
UserFunc -> NumParams++;
}
if (PTmp != NULL && PTmp -> NodeKind == PARAMETER) {
Name = PTmp -> PObj -> Name;
/* Make sure we do not have duplicated names in param. list. */
for (PObjTmp = UserFunc -> Params;
PObjTmp != NULL;
PObjTmp = PObjTmp -> Pnext) {
if (strcmp(Name, PObjTmp -> Name) == 0) {
IPGlblEvalError = IE_ERR_IP_USERFUNC_DUP_VAR;
sprintf(IPGlblCharData, "Func \"%s\", Variable \"%s\"",
UserFunc -> FuncName, Name);
InptEvalDeleteFunc(UserFunc, TRUE);
return;
}
}
/* Create a new object with same name but undefined type. */
if (UserFunc -> Params == NULL)
UserFunc -> Params = PObjTail =
IPAllocObject(Name, IP_OBJ_UNDEF, NULL);
else {
PObjTail -> Pnext = IPAllocObject(Name, IP_OBJ_UNDEF, NULL);
PObjTail = PObjTail -> Pnext;
}
/* Make sure there is no undefined object by that name in global */
/* list from the parsing stage. If so - remove it. */
if ((PObj = GetObject(Name)) != NULL &&
PObj -> ObjType == IP_OBJ_UNDEF)
DeleteObject(PObj, TRUE);
UserFunc -> NumParams++;
}
/* Allocate a "return" variable. */
UserFunc -> LocalVars = IPAllocObject("RETURN", IP_OBJ_UNDEF, NULL);
/* Isolate the body of the function while saving the list of local vars. */
for (Body = FuncDef -> Right, PTmp = FuncDef;
Body -> NodeKind == COLON && Body -> Left -> NodeKind == PARAMETER;
PTmp = Body, Body = Body -> Right) {
Name = Body -> Left -> PObj -> Name;
/* Make sure we do not have duplicated names in local vars list. */
for (PObjTmp = UserFunc -> Params;
PObjTmp != NULL;
PObjTmp = PObjTmp -> Pnext) {
if (strcmp(Name, PObjTmp -> Name) == 0) {
IPGlblEvalError = IE_ERR_IP_USERFUNC_DUP_VAR;
sprintf(IPGlblCharData, "Func \"%s\", Variable \"%s\"",
UserFunc -> FuncName, Name);
InptEvalDeleteFunc(UserFunc, TRUE);
return;
}
}
for (PObjTmp = UserFunc -> LocalVars;
PObjTmp != NULL;
PObjTmp = PObjTmp -> Pnext) {
if (strcmp(Name, PObjTmp -> Name) == 0) {
IPGlblEvalError = IE_ERR_IP_USERFUNC_DUP_VAR;
sprintf(IPGlblCharData, "Func \"%s\", Variable \"%s\"",
UserFunc -> FuncName, Name);
InptEvalDeleteFunc(UserFunc, TRUE);
return;
}
}
/* We found a local variable decl. Copy it to local variable list. */
/* Create a new object with same name but undefined type. */
UserFunc -> LocalVars =
IPAllocObject(Name, IP_OBJ_UNDEF, UserFunc -> LocalVars);
/* Make sure there is no undefined object by that name in global */
/* list from the parsing stage. If so - remove it. */
if ((PObj = GetObject(Name)) != NULL &&
PObj -> ObjType == IP_OBJ_UNDEF)
DeleteObject(PObj, TRUE);
}
/* Disconnect body of the function and save it in function definition. */
PTmp -> Right = NULL;
UserFunc -> Body = Body;
IritPrsrMarkToBeAssigned(Body);
if (InptPrsrTypeCheck(Body, 0) != ERROR_EXPR) {
if (NewFunc) {
UserFunc -> Pnext = UserDefinedFuncList;
UserDefinedFuncList = UserFunc;
}
}
else
InptEvalDeleteFunc(UserFunc, TRUE);
}
/*****************************************************************************
* DESCRIPTION: *
* Deletes/clears a user defined function structure. *
* *
* PARAMETERS: *
* UserFunc: To remove from global list. *
* DeleteSelf: If TRUE, free UserFunc as well. *
* *
* RETURN VALUE: *
* void *
*****************************************************************************/
static void InptEvalDeleteFunc(UserDefinedFuncDefType *UserFunc,
int DeleteSelf)
{
if (UserFunc -> Params != NULL)
IPFreeObject(UserFunc -> Params);
if (UserFunc -> LocalVars != NULL)
IPFreeObject(UserFunc -> LocalVars);
if (UserFunc -> Body != NULL)
InptPrsrFreeTree(UserFunc -> Body);
if (DeleteSelf) {
if (UserFunc == UserDefinedFuncList)
UserDefinedFuncList = UserDefinedFuncList->Pnext;
else if (UserDefinedFuncList != NULL) {
UserDefinedFuncDefType *TempFunc;
for (TempFunc = UserDefinedFuncList;
TempFunc -> Pnext != UserFunc && TempFunc -> Pnext != NULL;
TempFunc = TempFunc -> Pnext);
if (TempFunc && TempFunc->Pnext == UserFunc)
TempFunc -> Pnext = TempFunc -> Pnext -> Pnext;
}
IritFree((VoidPtr) UserFunc);
}
else {
UserFunc -> Params = UserFunc -> LocalVars = NULL;
UserFunc -> Body = NULL;
UserFunc -> NumParams = 0;
}
}
/*****************************************************************************
* DESCRIPTION: M
* Sets the debug level of user function calls. M
* *
* PARAMETERS: M
* DebugFuncLevel: Level of debugging user defined functions. M
* *
* RETURN VALUE: M
* void M
* *
* KEYWORDS: M
* InptPrsrDebugFuncLevel M
*****************************************************************************/
void InptPrsrDebugFuncLevel(int DebugFuncLevel)
{
GlblDebugFuncLevel = DebugFuncLevel;
}
/*****************************************************************************
* DESCRIPTION: M
* Invokes the evaluation of a user function. M
* The following steps are performed: M
* 1. A copy is made of parameter variables and local variables. M
* 2. Binding of given parameters to function parameters. M
* 3. The local variables and parameters are added to global variable list. M
* *
* PARAMETERS: M
* Root: Parse tree of user defined function. M
* InputParams: Parameters of the function. M
* *
* RETURN VALUE: M
* ParseTree *: Evaluated result. M
* *
* KEYWORDS: M
* InptEvalUserFunc M
*****************************************************************************/
ParseTree *InptEvalUserFunc(ParseTree *Root, ParseTree *InputParams[])
{
int i;
char Line[LINE_LEN];
UserDefinedFuncDefType
*UserFunc = Root -> UserFunc;
IPObjectStruct *PObj,
*RetVal = NULL,
*LastNewObj = NULL,
*Params = CopyObjectList(UserFunc -> Params, TRUE),
*ParamsLast = IritPrsrGetLastObj(Params),
*LocalVars = CopyObjectList(UserFunc -> LocalVars, TRUE),
*LocalVarsLast = IritPrsrGetLastObj(LocalVars),
*EntryGlblObjList = GlblObjList;
ParseTree
*Body = InptPrsrCopyTree(UserFunc -> Body);
if (GlblDebugFuncLevel > 0) {
sprintf(Line, "***** DEBUG FUNC: invoking \"%s\"\n",
UserFunc -> FuncName);
WndwInputWindowPutStr(Line);
}
if (LocalVars) {
/* Rebind local variables. */
for (PObj = LocalVars, i = 0; PObj != NULL; PObj = PObj -> Pnext) {
RebindVariable(Body, PObj, TRUE);
}
/* Chain the local variables into the global variable list. */
LastNewObj = LocalVarsLast;
LocalVarsLast -> Pnext = GlblObjList;
GlblObjList = LocalVars;
}
if (Params) {
/* Copy the parameter data into the parameters and rebind. */
for (PObj = Params, i = 0; PObj != NULL; PObj = PObj -> Pnext, i++) {
if (InputParams[i] -> PObj -> ObjType == IP_OBJ_UNDEF) {
IPGlblEvalError = IE_ERR_IP_OBJ_UNDEFINED;
sprintf(IPGlblCharData, "%s's parameter %d (%s).",
UserFunc -> FuncName, i + 1, PObj -> Name);
return NULL;
}
CopyObject(PObj, InputParams[i] -> PObj, FALSE);
RebindVariable(Body, PObj, TRUE);
if (GlblDebugFuncLevel > 2) {
sprintf(Line, "***** DEBUG FUNC %s: parameter %d =\n",
UserFunc -> FuncName, i);
WndwInputWindowPutStr(Line);
PrintObject(PObj);
}
}
/* Chain the parameters into the global variable list. */
if (LastNewObj == NULL)
LastNewObj = ParamsLast;
ParamsLast -> Pnext = GlblObjList;
GlblObjList = Params;
}
if (GlblDebugFuncLevel > 4) {
sprintf(Line, "***** DEBUG FUNC %s: global variable list =\n",
UserFunc -> FuncName);
WndwInputWindowPutStr(Line);
PrintObjectList(GlblObjList);
}
/* Invoke the body of the function/procedure. */
InptPrsrEvalTree(Body, 0);
if (strcmp(LocalVarsLast -> Name, "RETURN") != 0)
IritFatalError("Must have return value as last local\n");
if (UserFunc -> IsFunction) {
if (LocalVarsLast -> ObjType == IP_OBJ_UNDEF) {
IPGlblEvalError = IE_ERR_USER_FUNC_NO_RETVAL;
strcpy(IPGlblCharData, UserFunc -> FuncName);
}
else {
RetVal = CopyObject(NULL, LocalVarsLast, FALSE);
if (GlblDebugFuncLevel > 2) {
sprintf(Line, "***** DEBUG FUNC %s: return value =\n",
UserFunc -> FuncName);
WndwInputWindowPutStr(Line);
PrintObject(RetVal);
}
}
}
else {
if (GlblDebugFuncLevel > 0) {
sprintf(Line, "***** DEBUG FUNC: leaving \"%s\"\n",
UserFunc -> FuncName);
WndwInputWindowPutStr(Line);
}
}
/* Restore previous state of global var list, and free the local */
/* variables, parameters, and body. */
LastNewObj ->Pnext = NULL;
IPFreeObject(GlblObjList);
GlblObjList = EntryGlblObjList;
InptPrsrFreeTree(Body);
if (RetVal == NULL)
return NULL;
else {
Root -> PObj = RetVal;
return Root;
}
}